package cn.baage.campus.aspect;

import cn.baage.campus.annotation.ApiLog;
import cn.baage.campus.handler.ApiLogHandler;
import cn.baage.campus.model.dto.LogInfo;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @Description: 接口请求日志切面
 * @Author: 八阿哥
 * @url: baage.cn
 * @Version: 1.0
 **/
@Aspect
@Component
@Slf4j
public class ApiLogAspect {


    /** 以自定义 @ApiOperationLog 注解为切点，凡是添加 @ApiOperationLog 的方法，都会执行环绕中的代码 */
    @Pointcut("@annotation(cn.baage.campus.annotation.ApiLog)")
    public void apiLog() {}


    @Around("apiLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        LogInfo logInfo = new LogInfo();
        try {
            MDC.put("traceId", UUID.randomUUID().toString());
            long startTime = System.currentTimeMillis();
            // 获取被请求的类和方法以及入参
            String className = joinPoint.getTarget().getClass().getSimpleName();
            String methodName = joinPoint.getSignature().getName();
            String argsJsonStr = argsArrayToJson(joinPoint.getArgs());
            // 执行切点方法
            try {
                return joinPoint.proceed();
            } catch (Exception e) {
                // 处理异常
                logInfo.setErrMsg(e.getMessage());
                throw e;
            } finally {
                long executionTime = System.currentTimeMillis() - startTime;
                logInfo.setClassName(className);
                logInfo.setMethodName(methodName);
                logInfo.setArgs(argsJsonStr);
                logInfo.setStartTime(startTime);
                logInfo.setExecutionTime(executionTime);
                handlerLog(joinPoint, logInfo);
            }
        } catch (Exception e) {
            MDC.clear();
        }
        return null;
    }


    /**
     * 处理日志
     */
    private void handlerLog(ProceedingJoinPoint joinPoint, LogInfo logInfo) throws Exception {
        String traceId = MDC.get("traceId");
        logInfo.setTraceId(traceId);
        // 从 Method 中提取 apiLog 注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        ApiLog apiLog = signature.getMethod().getAnnotation(ApiLog.class);
        logInfo.setOperateType(apiLog.operateType());
        logInfo.setBusinessType(apiLog.businessType());
        Object o = apiLog.apiLogHandler().newInstance();
        if (!(o instanceof ApiLogHandler)) {
            o = Class.forName("cn.baage.campus.handler.apiLog.DefaultApiLogHandler").newInstance();
        }
        ApiLogHandler apiLogHandler = (ApiLogHandler) o;
        apiLogHandler.handler(logInfo);
    }


    /**
     * 处理参数
     */
    private String argsArrayToJson(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            return Arrays.stream(paramsArray).map(JSON::toJSONString).collect(Collectors.joining(","));
        }
        return params;
    }

}
